PHP tricks

PHP tricks

介绍一些PHP基础及CTF中的一些trick

PHP弱类型

PHP 松散类型比较表

''
1
2
3
4
5
6
7
8
'123' == 123
'abc' == 0
'123a' == 123
'0x01' == 1
'0e123456789' == '0e987654321'
[false] == [0] == [NULL] == ['']
NULL == false == 0
true == 1

AutoConvert

==比较时存在自动类型转换

  • 可转化为数字的字符串会转化为数字
    • 浮点数表示
      • 有包含 ‘.’,’e’ 或 ‘E’ 并且其数字值在整型的范围(PHP_INT_MAX )之内
    • 数字开头
    • 8进制
    • 16进制
  • 不可转化为数字的字符串与数字直接返回True

binarysafe and %00 truncation

PHP 中的 string的实现方式是一个由字节组成的数组再加上一个整数指明缓冲区长度

NULL bytes可以处于字符串任何位置

有几个函数会把 NUL 字节之后的数据全都忽略,这些函数是非二进制安全的函数。

  • ereg
  • strcoll

同时 php 5.3.4- 中,$_GET中的参数获取时会被截断!

常见过滤函数

addslashes()

' " \ NUll 

加上’\’处理

htmlspecialchars()

1
& <  >  "

第二个参数 ENT_QUOTES 存在 ,会过滤单引号

  • 不过滤 \ 反斜杠

mysql_[real_]escape_string

如下字符受影响【\x00】【\n】【\r】【\】【'】【"】【\x1a】
mysql_real_escape_string(string,$con)

mysql_real_escape is much safer than using addslashes

strip_tags(string[,allow])

注释总会被去掉

危险函数

下面的函数都有trick,大部分是出过题目的,例举了几个

部分函数传入数组返回NULL

  • substr()
  • md5()

strcmp(str1,str2)

  • str1<str2 返回-1

  • str1>str2 返回1

  • str1=str2返回0

  • 比较出错返回NULL,如下传入flag[]=…

    1
    2
    3
    if (strcmp($_GET['flag'], FLAG) == 0) {
    echo "success, flag:" . FLAG;
    }

curl()

  • file://xxx/etc/passwd 不管xxx是啥都是读本地的文件,造成lfi

  • 是弱二进制函数,可以用%00截断

由于还有二次url解码(相当于ssrf),可以用%2500截断

parse_url()

1
2
3
4
5
6
7
8
9
$url=parse_url($_SERVER['REQUEST_URI']);
var_dump($url);

http://localhost///web/trick1/parse.php?sql=select的方式可以使其返回False
array (size=0) empty
http://localhost/web/trick1//parse2.php?/home/binarycloud/则会被当做相对url,
此时的parse2.php?/home/binarycloud/都会被当做是url[‘path’]

parse_url()

preg_match()

  • preg_match存在贪婪匹配,那么我们可以喂给它一个超长的字符串让它去吃,导致pre_match消耗大量资源从而导致php超时,后面的php语句就不会执行。

    1
    2
    max_execution_time = 60	//最大时间设置,0表示无限时间
    memory_limit = 128M //最大内存设置
    • LCTF2017 SignupSystem
  • 若模式中有/e参数则会造成命令执行

  • 在PHP5.4.7以前,preg_replace的第一个参数可以利用\0进行截断,并将正则模式修改为e。

intval()

  • 不能识别除了”e”,数字,小数点,符号以外的字符,遇到则截断

  • 参数过大可造成溢出形成负数,这里涉及到整数溢出

    64位上,大于21位的数字

    1
    <?php echo invatl('4200000000000000000000');?>

in_arrary()

1
bool in_array(mixed $needle, array $haystack [,bool $strict = FALSE] )

在判断时,会自动做类型转换,除非第三个参数为True

1
if(in_arrary($_GET['typeid'],array(1,2,3,4))) echo "True";

如果输入?typeid=1’ union select ….会返回True从而可以注入sql语句

is_numeric()

当遇到hex时直接返回true
存在二次注入及XSS等风险

is_file ()

可以用伪协议绕过php://

switch 语句

auto ascii_to_int
“abcd”–>0

“123Test ”–>123

iconv()

在上传文件的过程中,如果目标使用的字符编码和访客操作系统使用的字符编码不同,可能导致上传后的文件名出现乱码。所以,开发者在获取文件名后,通常调用iconv()对其进行编码转换。 如果转换编码的操作在验证文件名后缀操作之后,那么我们可以利用iconv()特性,截断文件名,进而去除白名单中的后缀,造成文件上传漏洞。

数组永远大于数字

1
2
λ php -r "var_dump([]>23333);"
bool(true)

奇怪的恐龙特性 -安恒5月赛

? PHP的header函数一旦遇到\0、\r、\n这三个字符,就会抛出一个错误
? header之后没有exit的话会继续执行下去

$_REQUEST 覆盖

当 get 和 post 中有一个同名变量 data 时,在 request变量数组 中只会有post 的变量

$_SERVER[‘QUERY_STRING’] bypass

$_SERVER[‘QUERY_STRING’]` 获取的值是未经urldecode的,直接编码一下就饶过了

windows fistword爆破目录

http://www.venenof.com/index.php/archives/523/

webshell构造技巧

死亡exit()绕过

filter流绕过

1
php://filter/write=string.strip_tags|convert.base64-decode/resource=config.php

此时,PHP会先用strip_tags去除死亡exit,再将webshell用base64-decode还原,最终写入的文件中不再有死亡exit。

<?php头部过滤

<script:language=php>

BOM头绕过

BOM(Byte Order Mark)

大部分文本编辑软件都可以显示并编辑UTF-8编码的文件

而windows的记事本,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM).它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。

在1.php与2.php中输入同样的内容(注释中有中文‘你好’),当然两个文件都可以执行phpinfo()函数

1
2
3
4
5
6
7
8
9
#用记事本保存为utf-8
λ xxd 1.php
00000000: efbb bf3c 3f70 6870 0d0a 0970 6870 696e ...<?php...phpin
00000010: 666f 2829 3b2f 2fe4 bda0 e5a5 bd fo();//......

#notepad++正常保存
λ xxd 2.php
00000000: 3c3f 7068 700d 0a09 7068 7069 6e66 6f28 <?php...phpinfo(
00000010: 293b 2f2f e4bd a0e5 a5bd );//......

在这些文件开头已经有BOM的文件中,COOKIE无法送出(因为在COOKIE送出前PHP已经送出了文件头),所以登入和登出功能失效.一切依赖COOKIE、SESSION实现的功能全部无效.

PHP文件头BOM头问题

检测文件MIME类型的函数

这样文件开头不是<?,但是mime_content_type或是fileinfo函数判断它还是x-php类型的文件,

  • mime_content_type(5.3-)

  • fileinfo(extension=fileinfo)

    1
    2
    $fi = new finfo(FILEINFO_MIME_TYPE);
    echo $fi->file('1.php');

强网杯精英赛web题题解

<?=作php标签

<?= 的含义为<?php echo

是PHP 5.4.0以后的默认开启(不受short_open_tag选项控制)

注意不用?>结尾

###

https://tricking.io/category/php